package gis.lifay.sdk;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import hdf.hdflib.HDFException;
import hdf.object.*;
import hdf.object.h4.H4File;
import hdf.object.h4.H4SDS;
import hdf.view.Tools;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import java.awt.*;
import java.util.*;
import java.util.List;

/**
 *@ClassName HdfModel
 *@Description HDF模型
 *@Author lifay
 *@Date 2021/11/1 11:30
 **/
public class HdfModel {

    private String filePath;
    private boolean open = false;
    private FileFormat fileFormat;
    private Map<String, H4SDS> subDatasetMap;

    public HdfModel(String filePath) {
        if (!FileUtil.exist(filePath)) {
            throw HdfException.HDFFILE_NOT_FIND();
        }
        this.filePath = filePath;
    }

    /**
     * 初始化HDF实例
     * @throws Exception
     * @return 数据集数量
     */
    public int open() throws Exception {
        // retrieve an instance of H4File
        fileFormat = new H4File(filePath);
        if (fileFormat == null) {
            throw HdfException.HDFFILE_NOT_INIT();
        }
        //FileFormat fileFormat = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4);
        fileFormat.open();
        open = true;
        //初始化数据集列表
        TreeNode rootNode = fileFormat.getRootNode();
        Group root = (Group) ((DefaultMutableTreeNode) rootNode).getUserObject();
        subDatasetMap = new HashMap<>();
        loopSubDataSets(root, subDatasetMap);
        if (ObjectUtil.isEmpty(subDatasetMap)) {
            throw new HdfException("数据集加载失败");
        }
        return subDatasetMap.size();
    }

    /**
     * 获取所有数据集
     * @return
     * @throws Exception
     */
    public Map<String, H4SDS> getAllSubDataSets() throws Exception {
        checkOpen();
        return subDatasetMap;
    }

    /**
     * 获取所有数据集
     * @return
     * @throws Exception
     */
    public List<H4SDS> getAllSubDataSetList() throws Exception {
        Collection<H4SDS> values = subDatasetMap.values();
        List<H4SDS> list = new ArrayList<>();
        for (H4SDS value : values) {
            list.add(value);
        }
//        if (values instanceof Map) {
//            Map map = (Map) values;
//            return (List<H4SDS>) map.values();
//        }else if (values instanceof HashMap) {
//            HashMap map = (HashMap) values;
//            return (List<H4SDS>) map.values();
//        }else if (values.getClass().getName().equals("java.util.HashMap$Values")) {
//            HashMap map = (HashMap) values;
//            return (List<H4SDS>) map.values();
//        }
        return list;
    }

    private void checkOpen() {
        if (!open) {
            throw HdfException.HDFFILE_NOT_INIT();
        }
    }

    /**
     * 获取指定数据集
     * @return
     * @throws Exception
     */
    public H4SDS getSubDataSet(String datasetName) throws Exception {
        if (StrUtil.isBlank(datasetName)) {
            return null;
        }
        checkOpen();
        return subDatasetMap.get(datasetName);
    }

    /**
     * 递归获取数据集
     * @param root HDF对象
     * @param dataSets 数据集列表
     * @throws Exception
     */
    private void loopSubDataSets(HObject root, Map<String, H4SDS> dataSets) throws Exception {
        checkOpen();
        if (root instanceof Group) {
            Group group = (Group) root;
            for (HObject hObject : group.getMemberList()) {
                loopSubDataSets(hObject, dataSets);
            }
        } else if (root instanceof Dataset) {
            dataSets.put(root.getName(), (H4SDS) root);
        }
    }

    /**
     * 获取渲染后的图片
     * @param dataset 数据集实例
     * @param palette 调色板数据
     * @return
     * @throws Exception
     */
    public Image convertImage(H4SDS dataset, byte[][] palette) throws Exception {
        checkOpen();
        Object data = dataset.read();
        int h = (int) dataset.getDims()[0];
        int w = (int) dataset.getDims()[1];
        byte[] imageData = HDFUtil.getBytes(data, dataset.getImageDataRange(), w, h, false, null, false, null, null);
        if (palette == null) {
            palette = Tools.createNaturePalette();
        }
        Image image = hdf.view.Tools.createIndexedImage(null, imageData, palette, w, h);
        return image;
    }

    /**
     * 获取渲染后的图片
     * @param datasetName 数据集名称
     * @param palette 调色板数据
     * @return
     * @throws Exception
     */
    public Image convertImage(String datasetName, byte[][] palette) throws Exception {
        checkOpen();
        H4SDS dataset = getSubDataSet(datasetName);
        if (ObjectUtil.isEmpty(dataset)) {
            throw new Exception("未获取到数据集!");
        }
        Object data = dataset.read();
        int h = (int) dataset.getDims()[0];
        int w = (int) dataset.getDims()[1];
        byte[] imageData = HDFUtil.getBytes(data, dataset.getImageDataRange(), w, h, false, null, false, null, null);
        if (palette == null) {
            palette = Tools.createNaturePalette();
        }
        Image image = hdf.view.Tools.createIndexedImage(null, imageData, palette, w, h);
        return image;
    }

    /**
     * 获取渲染后的图片
     * @param dataset
     * @param palettePath 调色板文件路径
     * @return
     * @throws Exception
     */
    public Image convertImage(H4SDS dataset, String palettePath) throws Exception {
        checkOpen();
        byte[][] palette = null;
        if (StrUtil.isBlank(palettePath) || !FileUtil.exist(palettePath)) {
            palette = Tools.createNaturePalette();
        } else {
            palette = Tools.readPalette(palettePath);
        }
        return convertImage(dataset, palette);
    }

    public void close() {
        if (fileFormat != null) {
            try {
                fileFormat.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        this.open = false;
    }

    /**
     * 转换成数据集属性
     * @param h4SDS
     * @return
     * @throws HDFException
     */
    public DatasetProperties toDatasetPropeties(H4SDS h4SDS) throws HDFException {
        DatasetProperties hdfProperties = BeanUtil.copyProperties(h4SDS, DatasetProperties.class);
        hdfProperties.setFilename(h4SDS.getName());
        hdfProperties.setPath(h4SDS.getPath());
        List<Attribute> metadata = h4SDS.getMetadata();
        hdfProperties.setMetadatas(metadata);
        return hdfProperties;
    }

    /**
     * 获取指定数据的数据
     * @return
     * @throws Exception
     */
    public Object readDataArray(String datasetName) throws Exception {
        checkOpen();
        H4SDS dataset = getSubDataSet(datasetName);
        return dataset.read();
    }

    /**
     * 获取指定数据的元数据
     * @return
     * @throws Exception
     */
    public Map<String, Object> getDataMetaData(H4SDS h4SDS) throws Exception {
        Map<String, Object> map = new HashMap<>();
        List<Attribute> metadata = h4SDS.getMetadata();
        for (Attribute attribute : metadata) {
            String attributeName = attribute.getName();
            if (attributeName.equals("_FillValue")) {
                attributeName = "fill_value";
            }
            map.put(attributeName, attribute.getValue());
        }
        return map;
    }

}
